/* weehttp
 * Copyright (c) 2008 Jeffery Myers
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef _TEMPLATES_H_
#define _TEMPLATES_H_

#include <string>
#include <vector>
#include <map>

// called to get the code for a template variable
typedef void (*TemplateKeyCallback)(std::string &data, const std::string &key);

// called for logic statements, loops and if tests
// called repeatedly for each loop to know if it should be done.
// return true to do an instance of the loop
// return false to stop and continue the template
// for if test called to determine true or false
typedef bool (*TemplateTestCallback)(const std::string &key);

class TemplateMetaData
{
public:
  bool exists ( const char* key );
  bool exists ( const std::string &key ){return exists(key.c_str());}

  std::vector<std::string> get ( const char* key );
  std::vector<std::string> get ( const std::string &key ){return get(key.c_str());}

  std::string getFirst ( const char* key );
  std::string getFirst ( const std::string &key ){return getFirst(key.c_str());}

  void add ( const char* key, const char* val );
  void add ( const std::string &key, const std::string &val ){add(key.c_str(),val.c_str());}

protected:

  std::map< std::string, std::vector<std::string> > data;
};

class TemplateCallbackClass
{
public:
  virtual ~TemplateCallbackClass() {};
  virtual void keyCallback(std::string & /* data */, const std::string & /* key */) {};
  virtual bool loopCallback(const std::string &/* key */) { return false; }
  virtual bool ifCallback(const std::string &/* key */) { return false; }

  std::string templateParam;
};

class Templateiser : public TemplateCallbackClass
{
public:
  Templateiser(Templateiser * t = NULL);
  virtual ~Templateiser();

  void addKey(const char *key, TemplateKeyCallback callback);
  void addKey(const char *key, TemplateCallbackClass *callback);
  void clearKey(const char *key);
  void flushKeys(void);

  void addLoop(const char *loop, TemplateTestCallback callback);
  void addLoop(const char *loop, TemplateCallbackClass *callback);
  void clearLoop(const char *loop);
  void flushLoops(void);

  void addIF(const char *name, TemplateTestCallback callback);
  void addIF(const char *name, TemplateCallbackClass *callback);
  void clearIF(const char *name);
  void flushIFs(void);

  void processTemplate(std::string &code, const std::string &templateText);
  bool processTemplateFile(std::string &code, const char *file);

  void getTemplateMetaData(TemplateMetaData &metadata, const std::string &templateText);
  bool getTemplateFileMetaData(TemplateMetaData &metadata, const char *file);

  // for the default template tokens
  virtual void keyCallback(std::string &data, const std::string &key);
  virtual bool loopCallback(const std::string &key);
  virtual bool ifCallback(const std::string &key);

  void startTimer(void);
  void setPluginName(const char* name, const char* URL);

  void addSearchPath(const char* path);
  void flushSearchPaths(void);

  std::vector<std::string> getSearchPaths ( void ) { return filePaths;}

protected:
  typedef std::map<std::string,TemplateKeyCallback> KeyMap;
  typedef std::map<std::string,TemplateTestCallback> TestMap;
  typedef std::map<std::string,TemplateCallbackClass*> ClassMap;

  KeyMap keyFuncCallbacks;
  TestMap loopFuncCallbacks;
  TestMap ifFuncCallbacks;
  ClassMap keyClassCallbacks;
  ClassMap loopClassCallbacks;
  ClassMap ifClassCallbacks;

  bool callKey(std::string &data, const std::string &key);
  bool callLoop(const std::string &key, const std::string &param);
  bool callIF(const std::string &key,const std::string& param);

  void setDefaultTokens(void);

private:
  std::string::const_iterator readKey(std::string &key,
				      std::string::const_iterator inItr,
				      const std::string &str);
  std::string::const_iterator findNextTag(const std::vector<std::string> &keys,
					  std::string &endKey, std::string &code,
					  std::string::const_iterator inItr,
					  const std::string &str);

  void processInclude(std::string &code, std::string::const_iterator &inItr, const std::string &str);
  void processComment(std::string &code, std::string::const_iterator &inItr, const std::string &str);
  void replaceVar(std::string &code, std::string::const_iterator &itr, const std::string &str);
  void processIF(std::string &code, std::string::const_iterator &inItr, const std::string &str);
  void processLoop(std::string &code, std::string::const_iterator &inItr, const std::string &str);

  double startTime;
  std::string pluginName,baseURL;

  std::vector<std::string> filePaths;

  Templateiser *parent;
};

#endif //_TEMPLATES_H_


// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
